import { ECSErr } from "../err/ECSErr";
import { Pool } from "../util/Pool";
import { ECSEntity } from "./ECSEntity";
import { ECSScene } from "./ECSScene";

/**
 * [ECS]实体管理
 */
export class ECSEntityMgr {
	/** 实体对象池 */
	static pool = new Pool(ECSEntity);

	/** 当前实体最大id */
	protected _eid: number = 0;
	/** 场景里所有的实体 */
	protected _entityMap = new Map<number, ECSEntity>();
	/** 等待被添加的实体 */
	protected _waitAddEntities = new Set<ECSEntity>();
	/** 等待被移除的实体 */
	protected _waitRemoveEntities = new Set<ECSEntity>();
	/** 等待被清理的实体 */
	protected _waitFreeEntities = new Set<ECSEntity>();
	/** 实体发生添加变化 */
	protected _addDirty = false;
	/** 实体发生移除变化 */
	protected _removeDirty = false;

	constructor(
		/** 所在场景 */
		readonly scene: ECSScene
	) {}

	/**
	 * 获取一个新的实体id
	 */
	getId() {
		return ++this._eid;
	}

	/**
	 * 创建一个实体
	 * @param add 是否添加到场景 默认true
	 * @returns
	 */
	create(add = true) {
		const entity = ECSEntityMgr.pool.alloc();
		entity.id = this.getId();
		entity.scene = this.scene;
		if (add) {
			this.add(entity);
		}
		return entity;
	}

	/**
	 * 通过实体id获取场景中的实体
	 * @param id 实体id
	 */
	get(id: number) {
		return this._entityMap.get(id);
	}

	/**
	 * 遍历场景里的实体
	 * @param each 返回true时则返回对应实体
	 */
	each(each: (entity: ECSEntity) => any) {
		return this._entityMap.forEach(each);
	}

	/**
	 * 遍历寻找场景里的实体
	 * @param each 返回true时则返回对应实体
	 */
	find(each: (entity: ECSEntity) => any) {
		const keys = this._entityMap.keys();
		for (const key of keys) {
			const entity = this._entityMap.get(key);
			if (each(entity)) {
				return entity;
			}
		}
		return null;
	}

	/**
	 * 添加实体 在下一帧开始时才会真正被添加到场景
	 * @param entity 实体
	 */
	add(entity: ECSEntity) {
		if (!entity) {
			throw new ECSErr("添加不存在的实体");
		}
		this._addDirty = true;
		this._waitAddEntities.add(entity);
		entity.scene = this.scene;
		return entity;
	}

	/**
	 * 移除实体 在下一帧开始时才会真正从场景中移除
	 * @param entity 实体
	 */
	remove(entity: ECSEntity) {
		if (!entity) {
			throw new ECSErr("移除不存在的实体");
		}
		if (this._waitAddEntities.delete(entity)) {
			this._waitFreeEntities.add(entity);
			return;
		}
		this._removeDirty = true;
		this._waitRemoveEntities.add(entity);
		entity.removed = true;
	}

	/**
	 * 更新实体/组件添加
	 * 所有等待添加的实体/组件在这里统一添加
	 */
	updateAdd() {
		if (this._addDirty) {
			this._addDirty = false;

			if (this._waitAddEntities.size > 0) {
				this._waitAddEntities.forEach(e => {
					this._entityMap.set(e.id, e);
					e.onAdd();
					this.scene.filterMgr.onEntityAdd(e);
				});
				this._waitAddEntities.clear();
			}
		}

		this._entityMap.forEach(e => e.cmpMgr.updateAdd());
	}

	/**
	 * 更新实体/组件移除
	 * 所有等待移除的实体/组件在这里统一移除
	 */
	updateRemove() {
		if (this._removeDirty) {
			this._removeDirty = false;

			if (this._waitRemoveEntities.size > 0) {
				this._waitRemoveEntities.forEach(e => {
					this._entityMap.delete(e.id);
					this.scene.filterMgr.onEntityRemove(e);
					this._waitFreeEntities.add(e);
				});
				this._waitRemoveEntities.clear();
			}
		}

		this._entityMap.forEach(e => e.cmpMgr.updateRemove());
	}

	/**
	 * 更新实体/组件清理
	 */
	updateFree() {
		if (this._waitFreeEntities.size > 0) {
			this._waitFreeEntities.forEach(entity => {
				entity.onRemove();
				ECSEntityMgr.pool.free(entity);
			});
			this._waitFreeEntities.clear();
		}

		this._entityMap.forEach(e => e.cmpMgr.updateFree());
	}

	/**
	 * 场景停止时销毁
	 */
	destroy() {
		this._entityMap.forEach(e => {
			e.onRemove();
			ECSEntityMgr.pool.free(e);
		});
		this._waitAddEntities.forEach(e => {
			e.onRemove();
			ECSEntityMgr.pool.free(e);
		});
		this._waitFreeEntities.forEach(e => {
			e.onRemove();
			ECSEntityMgr.pool.free(e);
		});
		this._entityMap.clear();
		this._waitAddEntities.clear();
		this._waitRemoveEntities.clear();
		this._waitFreeEntities.clear();
	}
}
